package com.ruoyi.nettysocket;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.handler.socket.MySocketChannelInboundHandler1;
import com.ruoyi.protocol.MessageCodec1;
import com.ruoyi.protocol.ProtocolFrameDecoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

/**
 * Socket服务类。
 */
@Slf4j
@Component
public class SocketServer1 {
    @Value("${socket.port1}")
    private int port;

    private NioEventLoopGroup bossGroup;
    private NioEventLoopGroup workerGroup;

    public void startSocketServer() {
        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();

        LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
        MessageCodec1 messageCodec1 = new MessageCodec1();

        ByteBuf delimiter1 = ByteBufAllocator.DEFAULT.buffer();
        delimiter1.writeBytes(HexUtil.decodeHex("7e"));

        //ByteBuf delimiter1 = Unpooled.copiedBuffer("7e".getBytes());
        ByteBuf delimiter2 = ByteBufAllocator.DEFAULT.buffer();
        delimiter2.writeBytes(HexUtil.decodeHex("7e7e"));

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.channel(NioServerSocketChannel.class)
                .group(bossGroup, workerGroup)
                .option(ChannelOption.SO_BACKLOG, 1024)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(LOGGING_HANDLER);
                        //报文分隔符为"0x7e"，分割后的报文不包含分隔符。
                        pipeline.addLast(new ProtocolFrameDecoder(1024 * 300, delimiter1, delimiter2));
//                        pipeline.addLast(new ProtocolFrameDecoder(1024 * 300, delimiter1));
                        pipeline.addLast(messageCodec1);
                        pipeline.addLast(new MySocketChannelInboundHandler1());
                    }
                });
        bootstrap.bind(port).addListener((ChannelFutureListener) future1 -> {
            if (future1.isSuccess()) {
                log.info("SocketServer启动成功, port: {}", port);
                Channel channel = future1.channel();
                channel.closeFuture().addListener((ChannelFutureListener) future2 -> {
                    log.info("SocketServer已关闭！");
                    bossGroup.shutdownGracefully();
                    workerGroup.shutdownGracefully();
                });
            } else {
                log.error("SocketServer启动失败, cause: {}", future1.cause().getMessage());
            }
        });
    }

    /**
     * Springboot关闭时关闭SocketServer
     */
    @PreDestroy
    private void destroy() throws InterruptedException {
        log.info("NettyBooster.destroy --> : 关闭 SocketServer...");
        if (ObjectUtil.isNotNull(bossGroup)) {
            bossGroup.shutdownGracefully().sync();
        }
        if (ObjectUtil.isNotNull(workerGroup)) {
            workerGroup.shutdownGracefully().sync();
        }
        log.info("SocketServer.destroy --> : SocketServer已关闭!");
    }

}
